/*
 * Copyright 2008-2009 ArtisanLogic.com.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.artisanlogic.test;

import java.lang.reflect.Constructor;


// =====================================================================================================================
// Assert.java                                                                                   Created on Feb 20, 2009
// ---------------------------------------------------------------------------------------------------------------------
/**
 * Utility class providing extended assertions beyond the standard set provided by {@link junit.framework.Assert}
 * 
 * @author sean@artisanlogic.com
 * @author john@artisanlogic.com
 * @since 0.9-Beta
 */
// =====================================================================================================================
public class Assert extends junit.framework.Assert {
	
  public static void assertThrows(Class<? extends Exception> type, String message, Callback callback) throws Exception {
    try {
      callback.execute();
      org.junit.Assert.fail("An exception of type " + type.getCanonicalName() + " should have been thrown.");
    } catch(Exception ex) {
      org.junit.Assert.assertTrue("Expected an instance of " + type.getCanonicalName() + " to be thrown, but "
        + ex.getClass().getCanonicalName() + " was thrown instead.", ex.getClass().isAssignableFrom(type));
      org.junit.Assert.assertEquals(message, ex.getMessage());
    }
  }

  public static void assertThrows(Class<? extends Exception> type, Callback callback) throws Exception {
    assertThrows(type, null, callback);
  }

  public static void assertRequires(String name, Callback callback) throws Exception {
    assertThrows(IllegalArgumentException.class, "The " + name + " parameter cannot be null.", callback);
  }

  public static void assertImmutable(Callback callback) throws Exception {
    assertThrows(UnsupportedOperationException.class, callback);
  }

  public static void assertHashCodeConsistency(Object instance) throws Exception {
    for(int index = 0, expected = instance.hashCode(); index < 100; index++) {
      org.junit.Assert.assertEquals(expected, instance.hashCode());
    }
  }
  
  public static void assertHashCodeEquality(Object lhs, Object rhs) throws Exception {
    org.junit.Assert.assertEquals(lhs, rhs);
    org.junit.Assert.assertEquals(lhs.hashCode(), rhs.hashCode());
  }
  
  @SuppressWarnings("unchecked")
  public static void assertNoPublicConstructors(final Class<?> type) throws Exception {
    Constructor[] constructors = type.getConstructors();
    if(constructors.length > 0) {
      fail(type.getName() + " should not have any public constructors");
    }
    // For coverage
    
    Constructor constructor = type.getDeclaredConstructors()[0];
    constructor.setAccessible(true);
    constructor.newInstance(new Object[0]);
  }

}
